package com.xiaoxin.experience.util;


import org.springframework.scheduling.support.CronExpression;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * @author xiaoxin
 */
public class CronUtil
{
    private CronUtil() {}

    /**
     * check cron expression if valid
     * @return false if invalid or else true
     */
    public static boolean valid(String cron)
    {
        return CronExpression.isValidExpression(cron);
    }

    public static Date next(String cron)
    {
        if (valid(cron))
        {
            CronExpression parse = CronExpression.parse(cron);
            ZonedDateTime dateTime = ZonedDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());
            ZonedDateTime next = parse.next(dateTime);
            return next == null? null : Date.from(next.toInstant());
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public static <T>List<T> next(String cron, int expectTimes, Function<Date,T> apply)
    {
        if (Objects.isNull(apply))
        {
            apply = t->(T)t;
        }
        List<T> nextRunTimes = new ArrayList<>();

        if (valid(cron))
        {
            CronExpression parse = CronExpression.parse(cron);
            Date now = new Date();
            for (int i = 0; i < expectTimes; i++)
            {
                ZonedDateTime dateTime = ZonedDateTime.ofInstant(now.toInstant(), ZoneId.systemDefault());
                ZonedDateTime next = parse.next(dateTime);
                if (Objects.isNull(next))
                {
                    break;
                }
                else
                {
                    now = Date.from(next.toInstant());
                    nextRunTimes.add(apply.apply(now));
                }
            }

        }
        return nextRunTimes;
    }
}
